#include "testApp.h"


//--------------------------------------------------------------
void testApp::setup()
{
    //ofSetFrameRate(60.0f);
	ofSetVerticalSync(true);
	ofBackground(0,0,0);

    // GUI initialization
    gui.addSlider("Align factor", guiAlignFact, 0.0, 20.0);
    gui.addSlider("Separation factor", guiSepFact, 0.0, 20.0);
    gui.addSlider("Coherence factor", guiCohFact, 0.0, 20.0);
    gui.addSlider("Desired separation", guiSepRadius, 0.0, 150.0);
    gui.addSlider("Affect distance", guiAffectDist, 0.0, 300.0);
    gui.addSlider("Neighborhood angle", guiNeighborhoodAngleDeg, 0.0, 360.0);
    gui.addSlider("Max force", guiMaxForce, 0.0, 3.0);
    gui.addSlider("Max speed", guiMaxSpeed, 0.0, 3.0);
    gui.addSlider("Trail length", guiTrailLength, 0, 100);
    gui.addSlider("Boids count", guiNumBoids, 0, 1000);
    gui.loadFromXML();
    gui.show();

    // Create spatial database
	boidLqDB = lqCreateDatabase(0, 0, 0, ofGetWidth(), ofGetHeight(), 1, 10, 10, 1);

	setBoidsCount(guiNumBoids);

    // set random cohesion
    /*for(size_t i=0; i<boid_list.size(); i++) {
        float rand_float = ofRandom(0.0, 10.0);
        boid_list[i]->cohesionWeight = rand_float;
        boid_list[i]->boid_color.b = rand_float/10.0;
        boid_list[i]->boid_color.g = rand_float/10.0;
    }*/
}

//--------------------------------------------------------------
void testApp::update()
{
    checkParameters(); // update boid parameters from GUI sliders

    for(size_t i=0; i<boid_list.size(); i++) {
		boid_list[i]->flock();
    }

	for(size_t i=0; i<boid_list.size(); i++) {
		boid_list[i]->update();
	}

}

//--------------------------------------------------------------
void testApp::draw()
{
    for(size_t i=0; i<boid_list.size(); i++) {
        boid_list[i]->draw();
	}

    // Draw FPS counter
    static int i = 0;
    static double fps = ofGetFrameRate();
    if(i++ % 10 == 0)
        fps = ofGetFrameRate();
    ofSetColor(0xffffff);
    ofDrawBitmapString( " FPS: " + ofToString(fps, 1), 20, 20);

	gui.draw();

}


void testApp::checkParameters()
{
    setBoidsCount(guiNumBoids); // has to be done first

    static Boid reference_boid(NULL, NULL, -1); // create dummy boid object to compare with

    reference_boid.cohesionWeight = guiCohFact;
    reference_boid.separationWeight = guiSepFact;
    reference_boid.alignmentWeight = guiAlignFact;
    reference_boid.separationRadius = guiSepRadius;
    reference_boid.neighborhoodRadius = guiAffectDist;
    reference_boid.neighborhoodAngle = cos((guiNeighborhoodAngleDeg/2) * DEG_TO_RAD);
    reference_boid.maxForce(guiMaxForce);
    reference_boid.maxSpeed(guiMaxSpeed);
    reference_boid.trail_length = guiTrailLength;

    if (boid_list.size() > 0) {
        if (*boid_list[0] != reference_boid) {
            for (size_t i=0; i<boid_list.size(); i++) {
                *boid_list[i] = reference_boid;
            }
        }
    }
}


void testApp::setBoidsCount(int num_boids)
{
    const int current_count = boid_list.size();
    if (num_boids == current_count)
        return;

    int initialLastId; // the last boid in list's id nr before we change size of the list
    if (num_boids > current_count) { // add boids
        if (boid_list.empty()) // get proper id number
            initialLastId = 0;
        else
            initialLastId = (boid_list.back())->id();
        for (int i=0; i<(num_boids - current_count); i++) {
            boid_list.push_back(new Boid(&boid_list, boidLqDB, initialLastId + i));
        }
    }
    else if (num_boids < current_count) { // remove boids
        for (int i=0; i<(current_count - num_boids); i++) {
            Boid *tmp = boid_list.back();
            boid_list.pop_back();
            delete tmp;
        }
    }
}

//--------------------------------------------------------------
void testApp::keyPressed(int key){
	if(key == ' ') {
        gui.toggleDraw();
	}
	else if (key == 'f') {
        ofToggleFullscreen();
	}

}

//--------------------------------------------------------------
void testApp::keyReleased(int key){

}

//--------------------------------------------------------------
void testApp::mouseMoved(int x, int y){

}

//--------------------------------------------------------------
void testApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void testApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void testApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void testApp::windowResized(int w, int h){

}
